#pragma once
#include <sys/types.h>
#include <sys/socket.h>
#include "connection.hpp"
/*
    处理连接模块（IO+上层业务回调）：事件就绪负责将TCP缓冲区中的数据读取、写入、已经异常的处理
    模块中函数主要作为connection对象的注册函数使用
*/

class HanderConnection
{
public:
    HanderConnection(func_t parse):_parse(parse)
    {
    }

    void recver(Connection *cnt) // 读
    {
        errno = 0; // 全局错误码置0，因为以前的errno结果可能影响本次操作
        // 比如：上次errno==EAGAIN，但是本次recv获取到的是0或者-1（对端关闭或者异常），此时应该走到excepter函数中去处理
        // 但是errno==EAGAIN，就会再次派发，导致无法正常推出，可能导致阻塞
        while (true)
        {
            char buf[1024] = {0};
            int n = recv(cnt->getConnectionFd(), buf, sizeof(buf) - 1, 0);
            if (n > 0)
            {
                buf[n] = '\0';          // 消除换行符
                cnt->appendInbuff(buf); // 将每次从内核缓冲区读取的数据写到connection中维护的缓冲区（用户级缓冲区）
            }
            else
            {
                if (errno == EWOULDBLOCK || errno == EAGAIN)
                {
                    break;
                }
                else if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    cnt->_excepter(cnt);
                    return;
                }
            }
        }
        // 解包+上层业务处理
        _parse(cnt);
    }

    void sender(Connection *cnt) // 写
    {
        errno = 0;
        while (true)
        {
            int n = send(cnt->getConnectionFd(), cnt->getOutbuff().c_str(), cnt->getOutbuff().size(), 0);
            if (n > 0)
            {
                cnt->eraseOutbuff(n); // 将用户级发送缓冲区中已发送的数据清除
            }
            else if(n == 0)
            {
                break;
            }
            else
            {
                if (errno == EWOULDBLOCK || errno == EAGAIN)
                {
                    break; // tcp缓冲区写满
                }
                else if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    cnt->_excepter(cnt);
                    return;
                }
            }
        }
        // tcp发送缓冲区写满，但是还要进一步判断connection维护的发送缓冲区是否还有数据
        if (!cnt->isEmptyOutbuf())
        {
            // outbuf缓冲区还有数据，开启对写事件的关系
            cnt->_reactor->enableWriteRead(cnt->getConnectionFd(), true, true);
        }
        else
        {
            // outbuf没有数据，关闭对写事件的关系
            cnt->_reactor->enableWriteRead(cnt->getConnectionFd(), true, false);
        }
    }

    void excepter(Connection *cnt) // 异常
    {
        // 从reactor中删除监听文件描述符
        LOG(INFO, "link is close, fd:%d\n", cnt->getConnectionFd());
        cnt->_reactor->delConnection(cnt->getConnectionFd());
    }

private:
    func_t _parse; // 上层回调函数(解包+业务处理)
};